<?php

namespace App\Services;

use App\Models\Series;
use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Str;
use Illuminate\Support\Collection;

/**
 * 系列服务类
 * 
 * 职责：
 * - 处理系列相关的业务逻辑
 * - 系列创建、更新、删除的业务规则
 * - Slug生成和唯一性验证
 * - 系列文章排序管理
 */
class SeriesService extends BaseService
{
    /**
     * 创建新系列
     * 
     * @param array $data 系列数据
     * @param User $user 创建者
     * @return Series
     */
    public function create(array $data, User $user): Series
    {
        // 处理Slug：如果前端没有提供或为空，由后端生成
        $slug = $this->generateUniqueSlug($data['slug'] ?? null, $data['name']);

        // 创建系列
        $series = Series::create([
            'author_id' => $user->id,
            'name' => $data['name'],
            'slug' => $slug,
            'description' => $data['description'] ?? null,
            'featured_image' => $data['featured_image'] ?? null,
            'is_visible' => $data['is_visible'] ?? true,
            'meta_title' => $data['meta_title'] ?? null,
            'meta_description' => $data['meta_description'] ?? null,
            'post_count' => 0,
        ]);

        return $series;
    }

    /**
     * 更新系列
     * 
     * @param Series $series 系列模型
     * @param array $data 更新数据
     * @return Series
     */
    public function update(Series $series, array $data): Series
    {
        // 处理Slug：如果名称或slug更新，由后端统一处理
        if (isset($data['name']) || isset($data['slug'])) {
            $slug = $this->generateUniqueSlug(
                $data['slug'] ?? null,
                $data['name'] ?? $series->name,
                $series->id
            );
            $data['slug'] = $slug;
        }

        // 更新系列
        $series->update($data);

        return $series;
    }

    /**
     * 删除系列（软删除）
     * 
     * @param Series $series 系列模型
     * @return bool
     */
    public function delete(Series $series): bool
    {
        // 软删除系列
        $series->delete();

        // 将系列内的文章从系列中移除
        Post::where('series_id', $series->id)
            ->update([
                'series_id' => null,
                'series_order' => null,
                'sort_mode' => 'manual',
            ]);

        return true;
    }

    /**
     * 获取系列文章（根据 sort_mode 排序）
     * 
     * @param Series $series 系列模型
     * @param array $filters 过滤条件
     * @return Collection
     */
    public function getPosts(Series $series, array $filters = []): Collection
    {
        $query = $series->posts();

        // 只获取已发布的文章
        if (!isset($filters['include_drafts']) || !$filters['include_drafts']) {
            $query->published();
        }

        // 获取第一篇文章的 sort_mode（系列内所有文章的 sort_mode 应该相同）
        $firstPost = $query->first();
        $sortMode = $firstPost?->sort_mode ?? 'manual';

        // 根据 sort_mode 排序
        if ($sortMode === 'published_at') {
            $query->orderBy('published_at', 'asc');
        } else {
            $query->orderBy('series_order', 'asc');
        }

        return $query->get();
    }

    /**
     * 更新文章顺序（仅当 sort_mode = 'manual' 时有效）
     * 
     * @param Series $series 系列模型
     * @param array $postOrders 文章顺序数组，格式：['post_id' => order, ...]
     * @return bool
     */
    public function updatePostOrder(Series $series, array $postOrders): bool
    {
        // 验证所有文章都属于该系列
        $postIds = array_keys($postOrders);
        $posts = Post::where('series_id', $series->id)
            ->whereIn('id', $postIds)
            ->get();

        if ($posts->count() !== count($postIds)) {
            $this->throwException('部分文章不属于该系列', 400);
        }

        // 更新文章顺序
        foreach ($postOrders as $postId => $order) {
            Post::where('id', $postId)
                ->where('series_id', $series->id)
                ->update(['series_order' => $order]);
        }

        // 更新系列的文章数量
        $this->updatePostCount($series);

        return true;
    }

    /**
     * 更新排序模式
     * 
     * @param Series $series 系列模型
     * @param string $sortMode 排序模式：'manual' 或 'published_at'
     * @return bool
     */
    public function updateSortMode(Series $series, string $sortMode): bool
    {
        if (!in_array($sortMode, ['manual', 'published_at'])) {
            $this->throwException('无效的排序模式', 400);
        }

        // 更新系列内所有文章的 sort_mode
        Post::where('series_id', $series->id)
            ->update(['sort_mode' => $sortMode]);

        // 如果切换到按发布时间排序，需要重新计算 series_order
        if ($sortMode === 'published_at') {
            $posts = Post::where('series_id', $series->id)
                ->published()
                ->orderBy('published_at', 'asc')
                ->get();

            foreach ($posts as $index => $post) {
                $post->update(['series_order' => $index + 1]);
            }
        }

        return true;
    }

    /**
     * 更新系列的文章数量
     * 
     * @param Series $series 系列模型
     * @return void
     */
    public function updatePostCount(Series $series): void
    {
        $count = Post::where('series_id', $series->id)
            ->published()
            ->count();

        $series->update(['post_count' => $count]);
    }

    /**
     * 生成唯一的 slug
     * 
     * @param string|null $slug 提供的 slug
     * @param string $name 系列名称
     * @param int|null $excludeId 排除的系列 ID（用于更新时）
     * @return string
     */
    public function generateUniqueSlug(?string $slug, string $name, ?int $excludeId = null): string
    {
        // 如果提供了 slug，使用它；否则从名称生成
        $baseSlug = $slug ?: Str::slug($name);

        // 如果 slug 为空，使用默认值
        if (empty($baseSlug)) {
            $baseSlug = 'series-' . time();
        }

        // 检查唯一性
        $query = Series::where('slug', $baseSlug);
        if ($excludeId) {
            $query->where('id', '!=', $excludeId);
        }

        if ($query->exists()) {
            // 如果已存在，添加数字后缀
            $counter = 1;
            do {
                $newSlug = $baseSlug . '-' . $counter;
                $query = Series::where('slug', $newSlug);
                if ($excludeId) {
                    $query->where('id', '!=', $excludeId);
                }
                $counter++;
            } while ($query->exists());

            return $newSlug;
        }

        return $baseSlug;
    }
}

